package cn.xf.districonfig.client.processor;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import cn.xf.districonfig.client.property.SpringValue;
import cn.xf.districonfig.client.register.SpringValueRegistry;
import cn.xf.districonfig.client.util.PlaceHolderHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;

/**
 * spring的@Value注解扫描器
 * @Author fangxiaofan
 */
public class SpringValueProcessor extends BaseValueProcessor implements BeanFactoryPostProcessor,
        InitializingBean, BeanPostProcessor {

    private final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class);

    private static final ConcurrentHashMap<String, SpringValue> cacheMap = new ConcurrentHashMap();

    private PlaceHolderHelper placeHolderHelper;

    private SpringValueRegistry springValueRegistry;

    public ConcurrentHashMap<String, SpringValue> getCacheMap() {
        return cacheMap;
    }

    public void updateValue(String k, Object v) {
        boolean containsKey = cacheMap.containsKey(k);
        if (!containsKey) {
            return;
        }
        try {
            cacheMap.get(k).update(v);
        } catch (IllegalAccessException | InvocationTargetException e) {
            logger.error("Here an exception :", e);
        }
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        super.postProcessBeforeInitialization(bean, beanName);
        return bean;
    }

    @Override
    protected void processField(Object bean, String beanName, Field field) {

        // 用到@Value 注解
        Value value = field.getAnnotation(Value.class);
        if(value!= null){
            // 登记下来---保存
            Set<String> keys = placeHolderHelper.extractPlaceholderKeys(value.value());
            for (String key : keys){
                SpringValue springValue = new SpringValue(key,value.value(),bean,beanName,field,false);
                cacheMap.put(key,springValue);
            }
        }

    }

    @Override
    protected void processMethod(Object bean, String beanName, Method method) {
        //register @Value on method
        Value value = method.getAnnotation(Value.class);
        if (value == null) {
            return;
        }
        //skip Configuration bean methods
        if (method.getAnnotation(Bean.class) != null) {
            return;
        }
        if (method.getParameterTypes().length != 1) {
            logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters",
                bean.getClass().getName(), method.getName(), method.getParameterTypes().length);
            return;
        }

        Set<String> keys = placeHolderHelper.extractPlaceholderKeys(value.value());

        for (String key : keys) {
            SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false);
            springValueRegistry.register(beanFactory, key, springValue);
            logger.info("Monitoring {}", springValue);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        placeHolderHelper = beanFactory.getBean(PlaceHolderHelper.class);
        springValueRegistry = beanFactory.getBean(SpringValueRegistry.class);
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
